home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / scheme / siod / siod_v20.lha / siod.doc < prev    next >
Encoding:
Text File  |  1993-08-16  |  15.1 KB  |  441 lines

  1.  *                        COPYRIGHT (c) 1989 BY                             *
  2.  *        PARADIGM ASSOCIATES INCORPORATED, CAMBRIDGE, MASSACHUSETTS.       *
  3.  *        See the source file SLIB.C for more information.                  *
  4.  
  5. Documentation for Release 2.0 1-DEC-89, George Carrette
  6.  
  7. [Release Notes:]
  8.  
  9. 1.4 This release is functionally the same as release 1.3 but has been
  10. remodularized in response to people who have been encorporating SIOD
  11. as an interpreted extension language in other systems.
  12.  
  13. 1.5 Added the -g flag to enable mark-and-sweep garbage collection.
  14.     The default is stop-and-copy.
  15.  
  16. 2.0 Set_Repl_Hooks, catch & throw. 
  17.  
  18. gjc@paradigm.com
  19. George Carrette
  20.  
  21.    
  22. Paradigm Associates Inc          Phone: 617-492-6079
  23. 29 Putnam Ave, Suite 6
  24. Cambridge, MA 02138
  25.  
  26. [Files:]
  27.  
  28.  siod.h    Declarations 
  29.  slib.c    scheme library.
  30.  siod.c    a main program.
  31.  siod.scm  (optional) Some scheme code
  32.  
  33. [Motivation:]
  34.  
  35. The most obvious thing one should notice is that this lisp implementation 
  36. is extremely small. For example, the resulting binary executable file 
  37. on a VAX/VMS system with /notraceback/nodebug is 17 kilo-bytes.
  38.  
  39. Small enough to understand, the source file slib.c is 30 kilo-bytes.
  40.  
  41. Small enough to include in the smallest applications which require
  42. command interpreters or extension languages.
  43.  
  44. We also want to be able to run code from the book "Structure and
  45. Interpretation of Computer Programs." 
  46.  
  47. Techniques used will be familiar to most lisp implementors.  Having
  48. objects be all the same size, and having only two statically allocated
  49. spaces simplifies and speeds up both consing and gc considerably.  the
  50. MSUBR hack allows for a modular implementation of tail recursion,     
  51. an extension of the FSUBR that is, as far as I know, original.
  52. The optional mark and sweep garbage collector may be selected at runtime.
  53.  
  54. Error handling is rather crude. A topic taken with machine fault,
  55. exception handling, tracing, debugging, and state recovery which we
  56. could cover in detail, but is clearly beyond the scope of this
  57. implementation. Suffice it to say that if you have a good symbolic
  58. debugger you can set a break point at "err" and observe in detail all
  59. the arguments and local variables of the procedures in question, since
  60. there is no casting of data types. For example, if X is an offending
  61. or interesting object then examining X->type will give you the type,
  62. and X->storage_as.cons will show the car and the cdr.
  63.  
  64. [Garbage Collection:]
  65.  
  66. There are two storage management techniques which may be chosen at runtime
  67. by specifying the -g argument flag. 
  68.  
  69.  -g1 (the default) is stop-and-copy. This is the simplest and most
  70.      portable implementation. GC is only done at toplevel.
  71.  -g0 is mark-and-sweep. GC is done at any time, required or requested.
  72.      However, the implementation is not as portable.
  73.  
  74. Discussion of stop-and-copy follows:
  75.  
  76. As one can see from the source, garbage collection is really quite an easy
  77. thing. The procedure gc_relocate is about 25 lines of code, and
  78. scan_newspace is about 15.
  79.  
  80. The real tricks in handling garbage collection are (in a copying gc):
  81.  (1) keeping track of locations containing objects
  82.  (2) parsing the heap (in the space scanning)
  83.  
  84. The procedure gc_protect is called once (e.g. at startup) on each
  85. "global" location which will contain a lisp object.
  86.  
  87. That leaves the stack. Now, if we had chosen not to use the argument
  88. and return-value passing mechanism provided by the C-language
  89. implementation, (also known as the "machine stack" and "machine
  90. procedure calling mechanism) this lisp would be larger, slower, and
  91. rather more difficult to read and understand. Furthermore it would be
  92. considerably more painful to *add* functionality in the way of SUBR's
  93. to the implementation.
  94.  
  95. Aside from writing a very machine and compiler specific assembling language
  96. routine for each C-language implementation, embodying assumptions about
  97. the placement choices for arguments and local values, etc, we
  98. are left with the following limitation: "YOU CAN GC ONLY AT TOP-LEVEL"
  99.  
  100. However, this fits in perfectly with the programming style imposed in
  101. many user interface implementations including the MIT X-Windows Toolkit.
  102. In the X Toolkit, a callback or work procedure is not supposed to spend
  103. much time implementing the action. Therefore it cannot have allocated
  104. much storage, and the callback trampoline mechanism can post a work
  105. procedure to call the garbage collector when needed.
  106.  
  107. Our simple object format makes parsing the heap rather trivial.
  108. In more complex situations one ends up requiring object headers or markers
  109. of some kind to keep track of the actual storage lengths of objects
  110. and what components of objects are lisp pointers.
  111.  
  112.  
  113. Discussion of mark-and-sweep follows:
  114.  
  115. In a mark-and-sweep GC the objects are not relocated. Instead
  116. one only has to LOOK at objects which are referenced by the argument
  117. frames and local variables of the underlying (in this case C-coded)
  118. implementation procedures. If a pointer "LOOKS" like it is a valid
  119. lisp object (see the procedure mark_locations_array) then it may be marked,
  120. and the objects it points to may be marked, as being in-use storage which
  121. is not linked into the freelist in the gc_sweep phase.
  122.  
  123. Another advantage of the mark_and_sweep storage management technique is
  124. that only one heap is required.
  125.  
  126. This main disadvantages are:
  127. (1) start-up cost to initially link freelist.
  128.     (can be avoided by more general but slower NEWCELL code).
  129. (2) does not COMPACT or LOCALIZE the use of storage. This is POOR engineering
  130.     practice in a virtual memory environment.
  131. (2) the entire heap must be looked at, not just the parts with useful storage.
  132.  
  133. In general, mark-and-sweep is slower in that it has to look at more
  134. memory locations for a given heap size, however the heap size can
  135. be smaller for a given problem being solved. More complex analysis
  136. is required when READ-ONLY, STATIC, storage spaces are considered.
  137. Additionally the most sophisticated stop-and-copy storage management
  138. techniques take into account considerations of object usage temporality.
  139.  
  140. [Compilation:]
  141.  
  142. The code has been compiled and run by the author on Sun III and IV,
  143. Encore Multimax, 4.3BSD VAX, VAX/VMS, and AMIGA 500 using the Lattice C
  144. compiler.
  145.  
  146. On all unix machines use (with floating-point flags as needed)
  147.   
  148.   %cc -O -c siod.c
  149.   %cc -O -c slib.c
  150.   %cc -o siod siod.o slib.o
  151.  
  152. on VAX/VMS:
  153.  
  154.   $ cc siod
  155.   $ cc slib
  156.   $ link siod,slib,sys$input:/opt
  157.   sys$library:vaxcrtl/share
  158.   $ siod == "$" + F$ENV("DEFAULT") + "SIOD"
  159.  
  160. on AMIGA 500, ignore warning messages about return value mismatches,
  161.   %lc siod.c
  162.   %lc slib.c
  163.   %blink lib:c.o,siod.o,slib.o to siod lib lib:lcm.lib,lib:lc.lib,lib:amiga.lib
  164.  
  165.  
  166. [Invocation:]
  167.  
  168. siod [-hXXXXX] [-iXXXXX] [-gX]
  169.  -h where XXXXX is an integer, to specify the heap size, in obj cells,
  170.  -i where XXXXX is a filename to load before going into the repl loop.
  171.  -g where X = 1 for stop-and-copy GC, X = 0 for mark-and-sweep.
  172.  
  173.   Example:
  174.    siod -isiod.scm -h100000
  175.  
  176. [System:]
  177.  
  178. The interrupts called SIGINT and SIGFPE by the C runtime system are
  179. handled by invoking the lisp error procedure. SIGINT is usually caused
  180. by the CONTROL-C character and SIGFPE by floating point overflow or underflow.
  181.  
  182. [Syntax:]
  183.  
  184. The only special characters are the parenthesis and single quote.
  185. Everything else, besides whitespace of course, will make up a regular token.
  186. These tokens are either symbols or numbers depending on what they look like.
  187. Dotted-list notation is not supported on input, only on output.
  188.  
  189. [Special forms:]
  190.  
  191. The CAR of a list is evaluated first, if the value is a SUBR of type 9 or 10
  192. then it is a special form.
  193.  
  194. (define symbol value) is presently like (set! symbol value).
  195.  
  196. (define (f . arglist) . body) ==> (define f (lambda arglist . body))
  197.  
  198. (lambda arglist . body) Returns a closure.
  199.  
  200. (if pred val1 val2) If pred evaluates to () then val2 is evaluated else val1.
  201.  
  202. (begin . body) Each form in body is evaluated with the result of the last
  203. returned.
  204.  
  205. (set! symbol value) Evaluates value and sets the local or global value of
  206. the symbol.
  207.  
  208. (or x1 x2 x3 ...) Returns the first Xn such that Xn evaluated non-().
  209.  
  210. (and x1 x2 x3 ...) Keeps evaluating Xj until one returns (), or Xn.
  211.  
  212. (quote form). Input syntax 'form, returns form without evaluation.
  213.  
  214. (let pairlist . body) Each element in pairlist is (variable value).
  215. Evaluates each value then sets of new bindings for each of the variables,
  216. then evaluates the body like the body of a progn. This is actually
  217. implemented as a macro turning into a let-internal form.
  218.  
  219. (the-environment) Returns the current lexical environment.
  220.  
  221. [Macro Special forms:]
  222.  
  223. If the CAR of a list evaluates to a symbol then the value of that symbol
  224. is called on a single argument, the original form. The result of this
  225. application is a new form which is recursively evaluated.
  226.  
  227. [Built-In functions:]
  228.  
  229. These are all SUBR's of type 4,5,6,7, taking from 0 to 3 arguments
  230. with extra arguments ignored, (not even evaluated!) and arguments not
  231. given defaulting to (). SUBR's of type 8 are lexprs, receiving a list
  232. of arguments. Order of evaluation of arguments will depend on the
  233. implementation choice of your system C compiler.
  234.  
  235. consp cons car cdr set-car! set-cdr!
  236.  
  237. number? + - * / < > eqv?
  238. The arithmetic functions all take two arguments.
  239.  
  240. eq?, pointer objective identity. (Use eqv? for numbers.)
  241.  
  242. symbolconc, takes symbols as arguments and appends them. 
  243.  
  244. symbol?
  245.  
  246. symbol-bound? takes an optional environment structure.
  247. symbol-value also takes optional env.
  248. set-symbol-value also takes optional env.
  249.  
  250. env-lookup takes a symbol and an environment structure. If it returns
  251. non-nil the CAR will be the value of the symbol.
  252.  
  253. assq
  254.  
  255. read,print
  256.  
  257. eval, takes a second argument, an environment.
  258.  
  259. copy-list. Copies the top level conses in a list.
  260.  
  261. oblist, returns a copy of the list of the symbols that have been interned.
  262.  
  263. gc-status, prints out the status of garbage collection services, the
  264. number of cells allocated and the number of cells free. If given
  265. a () argument turns gc services off, if non-() turns gc services on.
  266. In mark-and-sweep storage management mode the argument only turns on
  267. and off verbosity of GC messages.
  268.  
  269. gc, does a mark-and-sweep garbage collection. If called with argument nil
  270. does not print gc messages during the gc.
  271.  
  272. load, given a filename (which must be a symbol, there are no strings)
  273. will read/eval all the forms in that file.
  274.  
  275. quit, will exit back to the operating system.
  276.  
  277. error, takes a symbol as its first argument, prints the pname of this
  278. as an error message. The second argument (optional) is an offensive
  279. object. The global variable errobj gets set to this object for later
  280. observation.
  281.  
  282. null?, not. are the same thing.
  283.  
  284. *catch tag exp, Sets up a dynamic catch frame using tag. Then evaluates exp.
  285.  
  286. *throw tag value, finds the nearest *catch with an EQ tag, and cause it to
  287. return value.
  288.  
  289. [Procedures in main program siod.c]
  290.  
  291. edit is a VMS specific function that takes a single filename argument
  292. and calls the EDT editor (as a procedure) to edit the file.
  293.  
  294. cfib is the same as standard-fib. You can time it and compare it with
  295. standard-fib to get an idea of the overhead of interpretation.
  296.  
  297. [Utility procedures in siod.scm:]
  298.  
  299. Shows how to define macros.
  300.  
  301. cadr,caddr,cdddr,replace,list.
  302.  
  303. (defvar variable default-value)
  304.  
  305. And for us old maclisp hackers, setq and defun, and progn, etc.
  306.  
  307. call-with-current-continuation
  308.  
  309. Implemented in terms of *catch and *throw. So upward continuations
  310. are not allowed.
  311.  
  312. [A streams implementation:]
  313.  
  314. The first thing we must do is decide how to represent a stream.
  315. There is only one reasonable data structure available to us, the list.
  316. So we might use (<stream-car> <cache-flag> <cdr-cache> <cdr-procedure>)
  317.  
  318. the-empty-stream is just ().
  319.  
  320. empty-stream?
  321.  
  322. head
  323.  
  324. tail
  325.  
  326. cons-stream is a special form. Wraps a lambda around the second argument.
  327.  
  328. *cons-stream is the low-level constructor used by cons-stream.
  329.  
  330. [Benchmarks:]
  331.  
  332. A standard-fib procedure is included in siod.scm so that everyone will
  333. use the same definition in any reports of speed. Make sure the return
  334. result is correct. use command line argument of
  335.  %siod -h100000 -isiod.scm
  336.  
  337. (standard-fib 10) => 55 ; 795 cons work.
  338. (standard-fib 15) => 610 ; 8877 cons work.
  339. (standard-fib 20) => 6765 ; 98508 cons work.
  340.  
  341. [Porting:]
  342.  
  343. The only code under #ifdef is the definition of myruntime, which
  344. should be defined to return a double float, the number of cpu seconds
  345. used by the process so far. It uses the the tms_utime slot, and assumes
  346. a clock cycle of 1/60'th of a second.
  347.  
  348. The stack and register marking code used in the mark-and-sweep GC
  349. is unlikely to work on machines that do not keep the procedure call
  350. stack in main memory at all times. It is assumed that setjmp saves
  351. all registers into the jmp_buff data structure.
  352.  
  353. There is a bit of type casting in close_open_files and vload. The
  354. pname of an un-interned symbol is used as a pointer to FILE. This
  355. saves the code (a conser, a print case, and two gc cases) of defining
  356. a new data type for keeping track of binary data.
  357.  
  358. If the stack is not always aligned (in LISP-PTR sense) then the 
  359. gc_mark_and_sweep procedure will not work properly. 
  360.  
  361. Example, assuming a byte addressed 32-bit pointer machine:
  362.  
  363. stack_start_ptr: [LISP-PTR(4)] 
  364.                  [LISP-PTR(4)]
  365.                  [RANDOM(4)]
  366.                  [RANDOM(2)]
  367.                  [LISP-PTR(4)]
  368.                  [LISP-PTR(4)]
  369.                  [RANDOM(2)]
  370.                  [LISP-PTR(4)]
  371.                  [LISP-PTR(4)]
  372. stack_end:       [LISP-PTR(4)]
  373.  
  374. As mark_locations goes from start to end it will get off proper alignment
  375. somewhere in the middle, and therefore the stack marking operation will
  376. not properly identify some valid lisp pointers.
  377.  
  378. Fortunately there is an easy fix to this. A more aggressive use of
  379. our mark_locations procedure will suffice.
  380.  
  381. For example, say that there might be 2-byte random objects inserted into
  382. the stack. Then use two calls to mark_locations:
  383.  
  384.  mark_locations(((char *)stack_start_ptr) + 0,((char *)&stack_end) + 0);
  385.  mark_locations(((char *)stack_start_ptr) + 2,((char *)&stack_end) + 2);
  386.  
  387. If we think there might be 1-byte random objects, then 4 calls are required:
  388.  
  389.  mark_locations(((char *)stack_start_ptr) + 0,((char *)&stack_end) + 0);
  390.  mark_locations(((char *)stack_start_ptr) + 1,((char *)&stack_end) + 1);
  391.  mark_locations(((char *)stack_start_ptr) + 2,((char *)&stack_end) + 2);
  392.  mark_locations(((char *)stack_start_ptr) + 3,((char *)&stack_end) + 3);
  393.  
  394.  
  395. [Interface to other programs:]
  396.  
  397. If your main program does not want to actually have a read/eval/print
  398. loop, and instead wants to do something else entirely, then use
  399. the routine set_repl_hooks to set up for procedures for:
  400.  
  401.  * putting the prompt "> " and other info strings to standard output.
  402.  
  403.  * reading (getting) an expression
  404.  
  405.  * evaluating an expression
  406.  
  407.  * printing an expression.
  408.  
  409. The routine get_eof_val may be called inside your reading procedure
  410. to return a value that will cause exit from the read/eval/print loop.
  411.  
  412. In order to call a single C function in the context of the repl loop,
  413. you can do the following:
  414.  
  415. int flag = 0;
  416.  
  417. void my_puts(st)
  418.  char *st;
  419. {}
  420.  
  421. LISP my_reader()
  422. {if (flag == 1)
  423.   return(get_eof_val());
  424.  flag == 1;
  425.  return(NIL);}
  426.  
  427. LISP my_eval(x)
  428.  LISP x;
  429. {call_my_c_function();
  430.  return(NIL);}
  431.  
  432. LISP my_print(x)
  433.  LISP x;
  434. {}
  435.  
  436. do_my_c_function()
  437. {set_repl_hooks(my_puts,my_read,my_eval,my_print);
  438.  repl_driver(1, /* or 0 if we do not want lisp's SIGINT handler */
  439.              0);}
  440.  
  441.